 /*
  * file.cpp
  *
  *  Copyright   : Copyright © 2011 Binda&Aeolus; All Rights Reserved
  *  Created on: 2011-3-20
  *  Author      :洪春晓
  */
 #include<math.h>
 #include<stdio.h>
 #include<stdlib.h>
 #include <malloc.h>
 #include<string.h>
 #include<fstream>
 #include<iostream>
 #include <windows.h>
 #include "Compression.h"

 using namespace std;

 #define   WIDTHBYTES(bits) (((bits)+31)/32*4)
 #define SUFFIX ".head"
 int file_fomat_size;

 typedef unsigned char BYTE;
 typedef unsigned short WORD;
 typedef unsigned long DWORD;
 typedef long LONG;


 typedef struct tagBITMAPFILEMYHEADER
 {
 	DWORD bfSize;
 	WORD   bfReserved1;
 	WORD   bfReserved2;
 	DWORD bfOffBits;
 } BITMAPFILEMYHEADER;

 typedef struct tagBITMAPINFOMYHEADER
 {
 	DWORD   biSize;
 	LONG    biWidth;
 	LONG    biHeight;
 	WORD    biPlanes;
 	WORD    biBitCount;
 	DWORD   biCompression;
 	DWORD   biSizeImage;
 	LONG    biXPelsPerMeter;
 	LONG    biYPelsPerMeter;
 	DWORD   biClrUsed;
 	DWORD   biClrImportant;
 } BITMAPINFOMYHEADER;


 typedef struct tagRGB_QUAD
 {
 	BYTE     rgbBlue;
 	BYTE     rgbGreen;
 	BYTE     rgbRed;
 	BYTE     rgbReserved;
 } RGB_QUAD;

 // 输出位图文件头
 void showBmpHead(BITMAPFILEMYHEADER* pBmpHead)
 {
 	cout<<"位图文件头:\n";
 	cout<<"文件大小:"<<pBmpHead->bfSize<<endl;
 	cout<<"保留字:"<<pBmpHead->bfReserved1<<endl;
 	cout<<"保留字:"<<pBmpHead->bfReserved2<<endl;
 	cout<<"实际位图数据的偏移字节数:"<<pBmpHead->bfOffBits<<endl;
 }

  //输出位图信息头
 void showBmpInforHead(tagBITMAPINFOMYHEADER* pBmpInforHead)
 {
 	cout<<"位图信息头:\n";
 	cout<<"结构体的长度:"<<pBmpInforHead->biSize<<endl;
 	cout<<"位图宽:"<<pBmpInforHead->biWidth<<endl;
 	cout<<"位图高:"<<pBmpInforHead->biHeight<<endl;
 	cout<<"biPlanes平面数:"<<pBmpInforHead->biPlanes<<endl;
 	cout<<"biBitCount采用颜色位数:"<<pBmpInforHead->biBitCount<<endl;
 	cout<<"压缩方式:"<<pBmpInforHead->biCompression<<endl;
 	cout<<"biSizeImage实际位图数据占用的字节数:"<<pBmpInforHead->biSizeImage<<endl;
 	cout<<"X方向分辨率:"<<pBmpInforHead->biXPelsPerMeter<<endl;
 	cout<<"Y方向分辨率:"<<pBmpInforHead->biYPelsPerMeter<<endl;
 	cout<<"使用的颜色数:"<<pBmpInforHead->biClrUsed<<endl;
 	cout<<"重要颜色数:"<<pBmpInforHead->biClrImportant<<endl;
 }

 void compressFile(char *yasoFile,char *strFile,FILE*pfile,int file_fomat_size,int pixel_num,int *pixel_sequence,int *store_size,int *length_sequ,int *pixel_len);
 void uncompressFile();

 int main()
 {
 	int *hdData = NULL;
 	BITMAPFILEMYHEADER   bitHead;
 	BITMAPINFOMYHEADER bitInfoHead;
 	WORD fileType;
 	FILE* pfile;

 	 //读入文件
 	char strFile[50] ;
 	char yasoFile[50];
 	cout<<"请输入要压缩的文件名称："<<endl;
 	cin>>strFile;
 	cout<<"请输入压缩后的文件名称："<<endl;
 	cin>>yasoFile;
 	 //文件指针指向文件
 	pfile = fopen(strFile,"rb");
 	if(pfile!=NULL)
 	{
 	 	cout<<"文件已成功打开."<<endl;

 	 	  		// 读取位图文件头信息
 	 	fread(&fileType,1,sizeof(WORD),pfile);
 	 	if(fileType != 0x4d42)
 	 	{
 	 	  	cout<<"这不是bmp格式的文件!";
 	 	  	return false;
 	 	}

 	 	fread(&bitHead,sizeof(BITMAPFILEMYHEADER),1,pfile);
 	 	showBmpHead(&bitHead);
 	 	cout<<endl<<endl;
 	   //读取位图信息头信息
 	    fread(&bitInfoHead,sizeof(BITMAPINFOMYHEADER),1,pfile);
 	 	showBmpInforHead(&bitInfoHead);
 	 	cout<<endl;
 	}
 	else
 	{
 	 	cout<<"文件打开失败!"<<endl;
 	 	return false;
 	}
 	tagRGB_QUAD *pRgb;
 	long nPlantNum;
 	if(bitInfoHead.biBitCount < 24) //有调色板
 	{
 	 	// 读取调色盘结信息
 	 	nPlantNum = long(pow(2,double(bitInfoHead.biBitCount)));     //   Mix color Plant Number;
 	 	pRgb=new tagRGB_QUAD [nPlantNum*sizeof(tagRGB_QUAD)];
 	 	memset(pRgb,0,nPlantNum*sizeof(tagRGB_QUAD));
 	 	fread(pRgb,4,nPlantNum,pfile);
 	 	cout<<"Color Plate Number: "<<nPlantNum<<endl;
 	}
 	int width = bitInfoHead.biWidth;
    int height = bitInfoHead.biHeight;

 	 // 分配内存空间把源图存入内存
 	 int l_width   = WIDTHBYTES(width* bitInfoHead.biBitCount);// 计算位图的实际宽度并确保它为32的倍数
 	 	 BYTE    *pColorData=new BYTE [height*l_width];
 	 	 memset(pColorData,0,height*l_width);
 	 	 long nData = height*l_width;
 	 	 file_fomat_size = sizeof(WORD)+sizeof(BITMAPFILEMYHEADER)+sizeof(BITMAPINFOMYHEADER)+nData;
 	 	  	// 把位图数据信息读到数组里
 	 	 fread(pColorData,1,nData,pfile);

 	 	  	// 将位图数据转化为RGB数据
 	 	 hdData = new int[width*height+1];
 	 	 if( bitInfoHead.biBitCount<24) //有调色板，即位图为非真彩色
 	 	 {
 	 	  cout<<"bitInfoHead.biBitCount<24"<<endl;
 	 	  int k;
 	 	  int index = 0;

 	 	  for(int i=0;i<height;i++)
 	 	  {
 	 	  	for(int j=0;j<width;j++)
 	 	  	{
 	 	  		BYTE mixIndex= 0;
 	 	  		k = i*l_width + j;
 	 	  		mixIndex = pColorData[k];

 	 	  		hdData[index+1] = (int) pRgb[mixIndex].rgbRed;
 	 	  		index++;
 	 	  	}
 	 	  }
 	 }
 	delete [] pRgb;
 	delete [] pColorData;

 	int pixel_num = bitInfoHead.biWidth*bitInfoHead.biHeight;
 	int *pixel_sequence = hdData;
 	int *store_size = new int[pixel_num+1];
 	int *length_sequ = new int[pixel_num+1];
 	int *pixel_len = new int[pixel_num+1];

 	//压缩文件
 	compressFile(yasoFile,strFile,pfile,file_fomat_size,pixel_num,pixel_sequence,store_size,length_sequ,pixel_len);

 	// 解压
 	uncompressFile();

 	fclose(pfile);
 	delete []hdData;
 	delete []store_size  ;
 	delete []length_sequ ;
 	delete []pixel_len  ;

 	return 0;
 }

void compressFile(char *yasoFile,char *strFile,FILE*pfile,int file_fomat_size,int pixel_num,int *pixel_sequence,int *store_size,int *length_sequ,int *pixel_len)
{
	int i=0;
	char buf;
 	char yssoheadFile[50];//保存文件头信息的文件
 	strcpy(yssoheadFile,yasoFile);
 	strcat(yssoheadFile,SUFFIX);
 	FILE* yssoheadfp=fopen(yssoheadFile,"wb");//保存头部信息
 	pfile=fopen(strFile,"rb"); //从fp中读取bmp的头文件格式

 	while (!feof(pfile))
 	{
 		fread(&buf, 1, 1, pfile);
 		if(i<=file_fomat_size) //如果当前是文件的头部信息，则把头部信息写到文件中
 			fwrite(&buf, 1, 1, yssoheadfp);
 		else
 			break;
 		i++;
 	}
 	SetFileAttributes(yssoheadFile,FILE_ATTRIBUTE_HIDDEN);
 	fclose(yssoheadfp);
 	fclose(pfile);

 	// 压缩
 	Compression file_compression(pixel_num,pixel_sequence,store_size,length_sequ,pixel_len);
 	file_compression.compress_file(yasoFile);
    cout<<"恭喜，压缩完毕！"<<endl;
}
/**
 *@ objFile 要解压的文件名称
 *@ jieyafile 解压后的文件名称
 **/
void inputFileName(char *objFile,char *jieyafile)
{
	cout<<"请输入要解压的文件名称："<<endl;
	cin>>objFile;

	cout<<"请输入解压后bmp文件的名称："<<endl;
	cin>>jieyafile;
}
void uncompressFile()
{
	char objFile[50]; //要解压的文件 名称
	char jieyafile[50];//解压后的文件名称
	char objheadFile[50];//保存文件头信息的文件

	inputFileName(objFile,jieyafile);
    strcpy(objheadFile,objFile);
    strcat(objheadFile,SUFFIX);
	FILE* des=fopen(jieyafile,"wb");
	FILE *yssoheadfp = fopen(objheadFile,"rb");
	char buf;
	while (!feof(yssoheadfp))
	{
		fread(&buf, 1, 1, yssoheadfp);
	    fwrite(&buf, 1, 1, des);
	}

	Compression file_uncompression;
	file_uncompression.uncompress_file(objFile,0); //将压缩文件的信息从strFile读入
	int p_num = 0;// 当前已读取的像素个数
	int index=1,j=1;
	while(1)
	{
		if(j<file_uncompression.length_sequ[index])
		{
			buf = file_uncompression.pixel_sequence[index];
			p_num++;
		}
		else if(p_num++ < file_uncompression.pixel_num)
		{
			index++;
			p_num++;
			j=0;
			 buf = file_uncompression.pixel_sequence[index];
		}
		else
			break;
		j++;
		fwrite(&buf, 1, 1, des);
	}
	cout<<"文件解压成功！"<<endl;
	fclose(des);
	fclose(yssoheadfp);
}
